package cn.itcast.account.service.impl;

import cn.itcast.account.entity.AccountFreeze;
import cn.itcast.account.mapper.AccountFreezeMapper;
import cn.itcast.account.mapper.AccountMapper;
import cn.itcast.account.service.TCCService;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * TCC余额扣减TCC业务实现类
 */
@Slf4j
@Service
public class TCCServiceImpl implements TCCService {

    //冻结表持久层接口
    @Autowired
    private AccountFreezeMapper accountFreezeMapper;

    @Autowired
    private AccountMapper accountMapper;

    /**
     * try
     * @param userId
     * @param money
     * @return
     */
    @Override
    @Transactional
    public boolean deduct(String userId, int money) {
        /*try {
            log.debug("尝试睡眠20秒，模拟try阻塞....会进行空回滚.....");
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }*/

        String xid = RootContext.getXID();//seata生成事务id
        //根据xid查询冻结表是否存在
        AccountFreeze af = accountFreezeMapper.selectById(xid);
        if(af != null){
            log.debug("解决了业务悬挂问题，直接返回");
            return true;
        }
        //1.保存记录到冻结表
        AccountFreeze accountFreeze = new AccountFreeze();
        accountFreeze.setXid(xid);//事务id
        accountFreeze.setUserId(userId);
        accountFreeze.setFreezeMoney(money);
        accountFreeze.setState(AccountFreeze.State.TRY);//当前状态为0 try 资源扣除与冻结
        accountFreezeMapper.insert(accountFreeze);
        log.debug("用户{}，冻结金额{}，成功了",userId,money);
        //2.扣减余额表
        int count = accountMapper.deduct(userId, money);
        log.debug("用户{}，扣减余额成功了，结果为{}",userId,count);
        return count == 1;
    }

    /**
     * confirm
     * @param actionContext
     * @return
     */
    @Override
    public boolean comfirm(BusinessActionContext actionContext) {
        String xid = actionContext.getXid();//事务id
        //String userId = actionContext.getActionContext("userId").toString();//获取try中参数
        int count = accountFreezeMapper.deleteById(xid);
        log.debug("事务id{},删除冻结记录成功了",xid);
        return count == 1;
    }

    /**
     * cancel
     * @param actionContext
     * @return
     */
    @Override
    @Transactional
    public boolean cancel(BusinessActionContext actionContext) {
        String xid = actionContext.getXid();//事务id
        //1.根据事务id查冻结表，获取冻结金额
        AccountFreeze accountFreeze = accountFreezeMapper.selectById(xid);
        String userId = actionContext.getActionContext("userId").toString();//获取try中参数
        if(accountFreeze == null){
            log.debug("冻结记录不存在。。。。。。");
            accountFreeze = new AccountFreeze();
            accountFreeze.setXid(xid);
            accountFreeze.setUserId(userId);
            accountFreeze.setFreezeMoney(0);
            accountFreeze.setState(AccountFreeze.State.CANCEL);
            accountFreezeMapper.insert(accountFreeze);
            log.debug("解决空回滚问题，往冻结表插入空回滚记录。。。。。。");
            return true;
        }
        //解决幂等问题
        if(AccountFreeze.State.CANCEL == accountFreeze.getState()){
            log.debug("已经取消过来，无需重复操作");
            return true;
        }
        Integer freezeMoney = accountFreeze.getFreezeMoney();
        //2.修改冻结表 状态2 冻结金额为0
        accountFreeze.setFreezeMoney(0);//金额已经回滚
        accountFreeze.setState(AccountFreeze.State.CANCEL);//分布式事务处理失败，记录（代表已经取消过）
        accountFreezeMapper.updateById(accountFreeze);
        log.debug("事务id{},更新冻结金额成功了,恢复冻结金额为{}",xid,freezeMoney);
        //3.修改账户余额 恢复余额（现有余额+冻结的钱）
        int count = accountMapper.refund(userId, freezeMoney);
        log.debug("事务id{},恢复余额成功了，用户id{}",xid,userId);
        return count == 1;
    }
}
